package com.filex.ads.nativeads;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.filex.ads.RequestParams;
import com.filex.ads.common.AdError;
import com.filex.ads.common.AdFormat;
import com.filex.ads.common.AdUrlGenerator;
import com.filex.ads.common.Preconditions;
import com.filex.ads.common.logging.Logger;
import com.filex.ads.common.utils.DeviceUtils;
import com.filex.ads.network.AdLoader;
import com.filex.ads.network.AdRequest;
import com.filex.ads.network.AdResponse;
import com.filex.ads.network.FilexNetworkError;
import com.filex.ads.volley.NetworkResponse;
import com.filex.ads.volley.VolleyError;

import java.lang.ref.WeakReference;


public class FilexNative {

    public interface NativeAdListener {
        void onNativeLoad(final NativeAd nativeAd);
        void onNativeFail(final AdError errorCode);
    }

    static final NativeAdListener EMPTY_NETWORK_LISTENER =
            new NativeAdListener() {
        @Override
        public void onNativeLoad(@NonNull final NativeAd nativeAd) {
            nativeAd.destroy();
        }
        @Override
        public void onNativeFail(final AdError error) {
        }
    };

    @NonNull private final WeakReference<Context> mContext;
    @NonNull private final String mPlacementId;
    @NonNull private NativeAdListener mAdListener;

    @Nullable private AdLoader mAdLoader;
    @NonNull private final AdLoader.Listener mInternalListener;
    @Nullable private AdRequest mNativeRequest;


    public FilexNative(@NonNull final Context context,
                       @NonNull final String placementId,
                       @NonNull final NativeAdListener adListener) {
        Preconditions.checkNotNull(context, "context may not be null.");
        Preconditions.checkNotNull(placementId, "PlacementId may not be null.");
        Preconditions.checkNotNull(adListener, "NativeAdListener may not be null.");
        mContext = new WeakReference<Context>(context);
        mPlacementId = placementId;
        mAdListener = adListener;
        mInternalListener = new AdLoader.Listener() {
            @Override
            public void onSuccess(@NonNull final AdResponse response) {
                onAdLoad(response);
            }

            @Override
            public void onErrorResponse(@NonNull final VolleyError volleyError) {
                onAdError(volleyError);
            }
        };
    }


    public void destroy() {
        mContext.clear();
        if (mNativeRequest != null) {
            mNativeRequest.cancel();
            mNativeRequest = null;
        }
        mAdLoader = null;

        mAdListener = EMPTY_NETWORK_LISTENER;
    }


    public void loadAd() {
        loadAd(null);
    }

    public void loadAd(RequestParams requestParams) {
        final Context context = getContextOrDestroy();
        if (context == null) {
            return;
        }
        if (!DeviceUtils.isNetworkAvailable(context)) {
            mAdListener.onNativeFail(AdError.CONNECTION_ERROR);
            return;
        }
        loadNativeAd(requestParams);
    }

    private void loadNativeAd(RequestParams params) {
        final Context context = getContextOrDestroy();
        if (context == null) {
            return;
        }
        final String requestUrl = new AdUrlGenerator(context)
                .withAdFormat(AdFormat.NATIVE)
                .withRequestParams(params)
                .generateUrlString(mPlacementId);
//        if (requestUrl != null) {
//            Logger.d("FilexNative Loading ad from: " + requestUrl);
//        }
        mAdLoader = new AdLoader(requestUrl, AdFormat.NATIVE, mPlacementId, context, mInternalListener);
        mNativeRequest = mAdLoader.loadAd();
    }


    private void onAdLoad(@NonNull final AdResponse response) {
        final Context context = getContextOrDestroy();
        if (context == null) {
            return;
        }
        Logger.d("Native ad request success." + response);
        mAdListener.onNativeLoad(new NativeAd(mPlacementId, new InternalNativeAd(context, response)));
    }

    private void onAdError(@NonNull final VolleyError volleyError) {
        Logger.d("Native ad request failed.", volleyError);
        if (volleyError instanceof FilexNetworkError) {
            FilexNetworkError error = (FilexNetworkError) volleyError;
            switch (error.getReason()) {
                case BAD_BODY:
                    mAdListener.onNativeFail(AdError.BAD_REQUEST);
                    return;
                case NO_FILL:
                    mAdListener.onNativeFail(AdError.NO_FILL);
                    return;
                case UNSPECIFIED:
                default:
                    mAdListener.onNativeFail(AdError.UNSPECIFIED);
                    return;
            }
        } else {
            // Process our other status code errors.
            NetworkResponse response = volleyError.networkResponse;
            if (response != null && response.statusCode >= 500 && response.statusCode < 600) {
                mAdListener.onNativeFail(AdError.INTERNAL_ERROR);
            } else if (response == null && !DeviceUtils.isNetworkAvailable(mContext.get())) {
                Logger.c(String.valueOf(AdError.CONNECTION_ERROR.toString()));
                mAdListener.onNativeFail(AdError.CONNECTION_ERROR);
            } else {
                mAdListener.onNativeFail(AdError.UNSPECIFIED);
            }
        }
    }

    @Nullable
    Context getContextOrDestroy() {
        final Context context = mContext.get();
        if (context == null) {
            destroy();
            Logger.d("Weak reference to Context in FilexNative became null. This instance" +
                    " of FilexNative is destroyed and No more requests will be processed.");
        }
        return context;
    }

}
